package org.hxzon.nioclient.impl;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.hxzon.nioclient.RequestQueue;
import org.hxzon.nioserver.BufferFactory;

public class LengthRequestQueueImpl implements RequestQueue {

    private final BufferFactory bufferFactory;
    private final Queue<ByteBuffer> bufQueue;
    private ByteBuffer bufDataCur;

    public LengthRequestQueueImpl(BufferFactory bufferFactory) {
        this.bufferFactory = bufferFactory;
        bufQueue = new ConcurrentLinkedQueue<ByteBuffer>();
    }

    //-----------
    public synchronized void enqueue(ByteBuffer bufDataNew) {
        bufDataNew.flip();
        //
        ByteBuffer bufForWriteLen = bufferFactory.newBuffer(4);
        bufForWriteLen.putInt(bufDataNew.remaining());
        bufForWriteLen.flip();
        bufQueue.add(bufForWriteLen);
        //
        bufQueue.add(bufDataNew);
    }

    public synchronized void drainTo(ByteChannel channel) throws IOException {
        if (bufDataCur == null) {
            bufDataCur = bufQueue.poll();
        }
        int count = -1;
        while (bufDataCur != null && count != 0) {//if no next bufDataCur,or channel can't write more,break
            while (bufDataCur.hasRemaining() && count != 0) {//if bufDataCur is ok,or channel can't write more,break
                count = channel.write(bufDataCur);
            }
            if (!bufDataCur.hasRemaining()) {//if bufDataCur is ok,next
                bufDataCur = bufQueue.poll();
            }
        }
    }

    public synchronized boolean isEmpty() {
        return bufDataCur == null && bufQueue.isEmpty();
    }

}
